﻿using System;
using System.Data.Entity.Database;
using System.Transactions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NpCrm.DataAccess.Repositories;

namespace NpCrm.Domain.Tests
{
    [TestClass]
    public class DonationRepositoryTests
    {
        private TransactionScope _scope;
        [TestInitialize]
        public void TestSetup()
        {
            DbDatabase.SetInitializer(new DropCreateDatabaseIfModelChanges<NpCrm.DataAccess.Core.NpCrmDataContext>());
            _scope = new TransactionScope(TransactionScopeOption.RequiresNew,
                                          new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted });
        }

        [TestCleanup]
        public void TestTeardown()
        {
            if (_scope != null)
                _scope.Dispose();
        }

        [TestMethod]
        public void CanAdd()
        {
            AddFakeDonation();
        }

        [TestMethod]
        public void CanGetById()
        {
            var fakeDonation = AddFakeDonation();
            using(var donationRepo = new DonationRepository())
            {
                var persistedDonation = donationRepo.GetById(fakeDonation.DonationId);
                Assert.IsNotNull(persistedDonation);
                Assert.AreEqual(fakeDonation.DonationId, persistedDonation.DonationId);
                CompareDonations(fakeDonation, persistedDonation);
            }
        }

        [TestMethod]
        public void CanUpdate()
        {
            var fakeDonation = AddFakeDonation();
            MonetaryDonation updateDonation;
            using (var donationRepo = new DonationRepository())
            {
                updateDonation = donationRepo.GetById(fakeDonation.DonationId) as MonetaryDonation;
                Assert.IsNotNull(updateDonation);
                updateDonation.UpdateDate = DateTime.Now;
                updateDonation.UpdateUserId = "brettfavre";
                updateDonation.Amount = (decimal) 2000.00;
                donationRepo.Commit();
            }
            using (var donationRepo = new DonationRepository())
            {
                var updatedDonation = donationRepo.GetById(updateDonation.DonationId) as MonetaryDonation;
                Assert.IsNotNull(updatedDonation);
                Assert.AreNotSame(updateDonation, updatedDonation);
                CompareDonations(updateDonation, updatedDonation);
            }
        }

        [TestMethod]
        public void CanDelete()
        {
            var fakeDonation = AddFakeDonation();
            using (var donationRepo = new DonationRepository())
            {
                var donationToDelete = donationRepo.GetById(fakeDonation.DonationId);
                donationRepo.Delete(donationToDelete);
                donationRepo.Commit();
            }
            using (var donationRepo = new DonationRepository())
            {
                var shouldBeNull = donationRepo.GetById(fakeDonation.DonationId);
                Assert.IsNull(shouldBeNull);
            }
        }

        public static Donation AddFakeDonation()
        {
            using (var donationRepo = new DonationRepository())
            {
                var fakeDonation = GetFakeDonation();
                donationRepo.Add(fakeDonation);
                donationRepo.Commit();
                Assert.IsTrue(fakeDonation.DonationId > 0);
                return fakeDonation;
            }
        }

        public static Donation GetFakeDonation()
        {
            var fakeContact = ContactRepositoryTests.AddFakeContact();
            return new MonetaryDonation
                       {
                           Amount = (decimal) 1000.00,
                           CreateDate = DateTime.Now,
                           CreateUserId = "ajohnson",
                           Contact = fakeContact
                       };
        }

        public static void CompareDonations(Donation expected, Donation actual)
        {
            Assert.AreEqual(expected.DonationId, actual.DonationId);
            Assert.AreEqual(expected.CreateUserId, actual.CreateUserId);
            Assert.AreEqual(expected.UpdateUserId, actual.UpdateUserId);
            if(expected is MonetaryDonation)
            {
                var expectedMonetaryDonation = expected as MonetaryDonation;
                var actualMonetaryDonation = actual as MonetaryDonation;
                Assert.IsNotNull(actualMonetaryDonation);
                Assert.AreEqual(expectedMonetaryDonation.Amount, actualMonetaryDonation.Amount);
            }
            if(expected is ClothingDonation)
            {
                var expectedClothingDonation = expected as ClothingDonation;
                var actualClothingDonation = actual as ClothingDonation;
                Assert.IsNotNull(actualClothingDonation);
                Assert.AreEqual(expectedClothingDonation.ItemQuantity, actualClothingDonation.ItemQuantity);
            }
        }
    }
}
